// gtest-runner.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <gtest/gtest.h>
#include <iostream>
#include <Shlwapi.h>
#include "PipingListener.h"
#include "RunConfiguration.h"


using namespace std;

typedef int (CALLBACK* LPFNDLLFUNC1)(void);

void dumpArgv(int argc, _TCHAR* argv[])
{
    for (int i = 0; i < argc; ++i) {
        wcout << i << _T(": ") << argv[i] << endl;
    }
}

/**
 * The following command line flags are expected:
 *   --gtest_list_tests  overloaded to indicate this is a list operation only
 *   --gtest_filter=     the filter to select tests to run
 *   --pipename=         the name of the named pipe to which to stream events
 *   --testlib=          the path to the DLL containing the tests to consider
 *   --libdir=           the directory containing DLL dependencies of the test
 *                       library. If unspecified, defaults to the directory
 *                       containing the test library.
 *   --selftest          whether to simply run the unit tests for this utility
 */
int _tmain(int argc, _TCHAR* argv[])
{
    GOOGLE_PROTOBUF_VERIFY_VERSION;

    RunConfiguration config;

    config.Parse(argc, argv);
    //dumpArgv(config.GetArgc(), config.GetArgv());

    // this call may modify both arguments, removing the recognized flags
    ::testing::InitGoogleTest(config.GetMutableArgc(), config.GetArgv());

    if (config.IsSelfTest()) {
        // run the self tests, and call it quits
        return RUN_ALL_TESTS();
    }

    if (config.GetTestLib().empty()) {
        cerr << "Must specify --testlib=DLLPATH" << endl;
        return 1;
    }

    if (! PathFileExists(config.GetTestLib().c_str())) {
        cerr << "Library not found at the specified path." << endl;
        return 1;
    }

    // add the directory containing the library to the DLL search path
    if (! SetDllDirectory(config.GetLibDir().c_str())) {
        cout << "Could not set DLL directory [" << GetLastError() << "]" << endl;
    }

    HMODULE hModule = LoadLibrary(config.GetTestLib().c_str());

    if (! hModule) {
        cerr << "Library could not be loaded [" << GetLastError() << "]" << endl;
        cerr << "Ensure all DLL dependencies are on the DLL search path." << endl;
        return 1;
    }

    int result = 0;

    if (config.IsListOperation()) {
        result = RUN_ALL_TESTS();
    }
    else {
        if (! config.GetPipeName().empty()) {
            HANDLE hPipe = CreateFile( 
                config.GetPipeName().c_str(),
                GENERIC_WRITE, 
                0,               // no sharing 
                NULL,            // default security attributes
                OPEN_EXISTING,   // opens existing pipe 
                0,               // default attributes 
                NULL);           // no template file 


            if (hPipe == INVALID_HANDLE_VALUE) {
                cerr << "Could not connect to named pipe ";
                wcerr << config.GetPipeName();
                cerr << " [" << GetLastError() << "]" << endl;
                return 1;
            }

            PipingListener* pListener = new PipingListener(hPipe);

            // add the listener, without removing any existing ones. The test
            // framework takes ownership of the listener.
            ::testing::UnitTest::GetInstance()->listeners().Append(pListener);

            // run the tests, and wait until the data has been read from the
            // pipe before exiting
            result = RUN_ALL_TESTS() && FlushFileBuffers(hPipe);

            CloseHandle(hPipe);
        }
        else {
            result = RUN_ALL_TESTS();
        }
    }

    // not necessary, and causes an access violation!
    //FreeLibrary(hModule);

    return result;
}
